#include <stdio.h>  // 包含标准输入输出库，用于printf, scanf, fflush, perror
#include <stdlib.h> // 包含标准库，用于exit, execvp
#include <unistd.h> // 包含POSIX标准库，用于fork, execvp, pipe, dup2, close, waitpid
#include <string.h> // 包含字符串处理库，用于memset
#include <fcntl.h>  // 包含文件控制库，用于open函数及其标志O_CREAT, O_TRUNC, O_WRONLY, O_APPEND
#include <ctype.h>  // 包含字符测试库，用于isspace函数
#include <sys/wait.h>
#define MAX_CMD 1024
char command[MAX_CMD];

int do_face()
{
    memset(command, 0x00, MAX_CMD);
    printf("minishell$ ");
    fflush(stdout);
    if (scanf("%[^\n]%*c", command) == 0)
    {
        getchar(); // 清除输入缓冲区中的换行符
        return -1;
    }
    return 0;
}
char **do_prase(char *buff)
{
    int argc = 0;
    static char *argv[64];
    char *ptr = buff;

    while (*ptr != '\0')
    {
        while (isspace(*ptr))
        {
            ptr++;
        }
        if (*ptr != '\0')
        {
            argv[argc++] = ptr;
            while ((!isspace(*ptr)) & (*ptr != '\0'))
            {
                ptr++;
            }
            if (*ptr != '\0')
            {
                *ptr = '\0';
                ptr++;
            }
        }
    }
    argv[argc] = NULL;
    return argv;
}
int do_readirect(char *buff)
{
    char *ptr = buff;
    char *file = NULL;
    int ype = 0;
    int fd;
    int redirece_type = -1;
    while (*ptr != '\0')
    {
        if (*ptr == '>')
        {
            *ptr++ = '\0';
            redirece_type++;
            if (*ptr == '>')
            {
                *ptr++ = '\0';
                redirece_type++;
            }
            while (isspace(*ptr))
            {
                ptr++;
            }
            file = ptr;
            while ((!isspace(*ptr)) & *ptr != '\0')
            {
                ptr++;
            }
            *ptr = '\0';
            if (redirece_type == 0)
            {
                fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0664);
            }
            else
            {
                fd = open(file, O_CREAT | O_APPEND | O_WRONLY, 0664);
            }
            if (fd < 0)
            {
                perror("open redirect file error");
            }
            dup2(fd, 1);
            close(fd);
        }
        ptr++;
    }
}

char *pipe_command[MAX_CMD / 2 + 2];
int do_command(char *buff)
{
    int pipe_num = 0;
    char *ptr = buff;
    pipe_command[pipe_num] = ptr;
    while (*ptr != '\0')
    {
        if (*ptr == '|')
        {
            pipe_num++;
            *ptr++ = '\0';
            pipe_command[pipe_num] = ptr;
            continue;
        }
        ptr++;
    }
    pipe_command[pipe_num + 1] = NULL;
    return pipe_num;
}
int do_pipe(int pipe_num)
{
    int i;
    pid_t pid;
    int pipes[32][2]; // 最多支持 32 段命令（31 根管道）

    // 1) 为每两个相邻命令创建一根管道
    for (i = 0; i < pipe_num; ++i)
    {
        if (pipe(pipes[i]) < 0)
        {
            perror("pipe creation failed");
            exit(EXIT_FAILURE);
        }
    }

    // 2) 保存所有子进程的 PID，方便最后统一 wait
    pid_t children[32] = {0};

    // 3) 依次 fork 每一段命令
    for (i = 0; i <= pipe_num; ++i)
    {
        pid = fork();
        if (pid < 0)
        {
            perror("fork failed");
            exit(EXIT_FAILURE);
        }

        if (pid == 0)
        {
            // —— 子进程逻辑 ——
            // 3.1 先做重定向（> 或 >>）
            do_readirect(pipe_command[i]);

            // 3.2 如果不是第 0 段，重定向 stdin 从上一根管道读端读
            if (i > 0)
            {
                dup2(pipes[i - 1][0], STDIN_FILENO);
            }
            // 3.3 如果不是最后一段，重定向 stdout 到下一根管道写端
            if (i < pipe_num)
            {
                dup2(pipes[i][1], STDOUT_FILENO);
            }

            // 3.4 关闭掉所有管道描述符（读/写端都关）
            for (int j = 0; j < pipe_num; ++j)
            {
                close(pipes[j][0]);
                close(pipes[j][1]);
            }

            // 3.5 解析当前命令段参数并 exec
            char **argv = do_prase(pipe_command[i]);
            execvp(argv[0], argv);

            // execvp 返回即为出错
            perror("execvp failed");
            exit(EXIT_FAILURE);
        }

        // —— 父进程逻辑(在这里什么都不做) ——
        children[i] = pid;
    }

    // 4) 在父进程中，关闭所有管道端
    for (i = 0; i < pipe_num; ++i)
    {
        close(pipes[i][0]);
        close(pipes[i][1]);
    }

    // 5) 等待所有子进程结束
    for (i = 0; i <= pipe_num; ++i)
    {
        waitpid(children[i], NULL, 0);
    }

    return 0;
}
int main(int argc, char *argv[])
{
    int num = 0;
    while (1)
    {
        if (do_face() < 0)
        {
            continue;
        }
        num = do_command(command);
        do_pipe(num);
    }
    return 0;
}